package org.skatiger.jrove.spring.view;

import java.util.Collections;
import java.util.List;

import javax.el.ELContextListener;
import javax.el.ELResolver;
import javax.servlet.ServletContext;

import org.skatiger.jrove.Configurator;
import org.skatiger.jrove.JroveFactory;
import org.skatiger.jrove.compiler.Compiler;
import org.skatiger.jrove.compiler.SAXCompiler;
import org.skatiger.jrove.impl.DefaultConfigurator;
import org.skatiger.jrove.impl.DefaultJroveFactory;
import org.skatiger.jrove.servlet.ServletResourceResolver;
import org.skatiger.jrove.util.AssertUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.context.ServletContextAware;

public class JroveConfigurer implements InitializingBean, ServletContextAware,
        JroveConfig {
    private static final Logger logger = LoggerFactory
            .getLogger(JroveConfigurer.class);

    private JroveFactory _jroveFactory;
    private DefaultConfigurator _configurator;
    private ServletContext _servletContext;
    private List<ELContextListener> _elContextListeners = Collections
            .emptyList();
    private List<ELResolver> _elResolvers = Collections.emptyList();

    private String[] tagLibraries;
    private String[] tagDecorators;

    public void setTagLibraries(String[] tagLibraries) {
        this.tagLibraries = tagLibraries;
    }

    public void setTagDecorators(String[] tagDecorators) {
        this.tagDecorators = tagDecorators;
    }

    public void setElContextListeners(List<ELContextListener> _elContextListeners) {
        this._elContextListeners = _elContextListeners;
    }

    public void setElResolvers(List<ELResolver> _elResolvers) {
        this._elResolvers = _elResolvers;
    }

    /**
     * Initialize the ViewHandler during its first request.
     */
    protected void initialize() {
        synchronized (this) {
            if (this._jroveFactory == null) {
                if (this._configurator == null) {
                    autodetectConfigurator();
                }
                if (logger.isInfoEnabled()) {
                    logger.info("Initializing Jrove Configurer");
                }
                Compiler c = this.createCompiler();
                c.initialize(this._configurator);
                this._jroveFactory = this.createJroveFactory(_configurator, c);
                logger.info("Initialization Successful...");
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.skatiger.jrove.spring.view.JroveConfig#getJroveFactory()
     */
    public JroveFactory getJroveFactory() {
        return _jroveFactory;
    }

    public DefaultConfigurator getConfigurator() {
        return _configurator;
    }

    private Compiler createCompiler() {
        return new SAXCompiler();
    }

    private JroveFactory createJroveFactory(Configurator config, Compiler c) {
        return new DefaultJroveFactory(c, config);
    }

    /**
     * Autodetect a {@link Configurator} object.
     * 
     * @return the Configuration instance to use for FreeMarkerViews
     * @throws BeansException
     *             if no Configuration instance could be found
     * @see #getApplicationContext
     * @see #setConfiguration
     */
    protected Configurator autodetectConfigurator() throws BeansException {
        if (this._configurator == null) {
            // try {
            // this.config = (Configuration) BeanFactoryUtils
            // .beanOfTypeIncludingAncestors(applicationContext,
            // Configuration.class, true, false);
            // if (logger.isInfoEnabled()) {
            // logger.info("use application context a single ResourceResovler bean");
            // }
            //
            // } catch (NoSuchBeanDefinitionException ex) {
            AssertUtil.notNull(_servletContext);
            ServletResourceResolver resourceResolver = new ServletResourceResolver();
            resourceResolver.prepareServletContext(_servletContext);
            DefaultConfigurator _config = new DefaultConfigurator(
                    resourceResolver);

            // put ELContextListeners
            for (ELContextListener contextListener : _elContextListeners) {
                _config.addELContextListener(contextListener);
            }
            // put ELResolver
            for (ELResolver resolver : _elResolvers) {
                _config.addELResolver(resolver);
            }
            // tagLibraries
            if (tagLibraries != null) {
                _config.setLibraries(tagLibraries);
            }
            // tagDecorators
            if (tagDecorators != null) {
                _config.setTagDecorators(tagDecorators);
            }
            this._configurator = _config;
            if (logger.isInfoEnabled()) {
                logger.info("build DefaultConfiguration success!");
            }
            // }
        }
        return this._configurator;
    }

    public void afterPropertiesSet() throws Exception {
        initialize();
    }

    public void setServletContext(ServletContext servletContext) {
        this._servletContext = servletContext;
    }

}
